package indi.zhifa.study2024.nbr.busycore.logic.curd.init.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import indi.zhifa.core.common.util.CommonUtil;
import indi.zhifa.core.common.web.entity.response.RestResponse;
import indi.zhifa.study2024.common.auth.util.DatasourceSetUtil;
import indi.zhifa.study2024.common.auth.util.billNo.BillNoUtil;
import indi.zhifa.study2024.nbr.busycore.gen.busy.account.po.GenEnterpriseEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.account.po.GenRoleEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.account.po.GenUserEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.account.service.IGenEnterpriseDbService;
import indi.zhifa.study2024.nbr.busycore.gen.busy.consign.po.GenConsignEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.consign.po.GenConsignHeaderEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.consign.service.IGenConsignDbService;
import indi.zhifa.study2024.nbr.busycore.gen.busy.consign.service.IGenConsignHeaderDbService;
import indi.zhifa.study2024.nbr.busycore.gen.busy.define.po.GenCustomerEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.define.po.GenItemEntity;
import indi.zhifa.study2024.nbr.busycore.gen.busy.define.service.IGenCustomerDbService;
import indi.zhifa.study2024.nbr.busycore.gen.busy.define.service.IGenItemDbService;
import indi.zhifa.study2024.nbr.busycore.logic.curd.init.IInitDataService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.client.RestClient;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@RequiredArgsConstructor
@Component
public class InitDataServiceImpl implements IInitDataService {

    final IGenEnterpriseDbService mGenEnterpriseDbService;
    final IGenCustomerDbService mCustomerDbService;
    final IGenItemDbService mItemDbService;
    final IGenConsignDbService mConsignDbService;
    final IGenConsignHeaderDbService mConsignHeaderDbService;
    final BillNoUtil mBillNoUtil;
    final PlatformTransactionManager mTransactionManager;

    @Data
    public static class RegisterRequest {
        String enpName;
        String enpDesc;
        String bossUserName;
        String bossUserPassword;
        String bossNickName;
    }

    @Data
    public static class RegisterResponse {
        GenEnterpriseEntity enterpriseInfo;
        GenUserEntity userInfo;
        List<GenRoleEntity> initRoleList;
    }

    @Data
    public static class LoginRequest {
        String username;
        String password;
    }

    @Data
    public static class LoginResponse{
        GenUserEntity userInfo;
        GenEnterpriseEntity enterpriseInfo;
        String token;
    }

    @Data
    public static class AddUserRequest {
        String name;
        String nickname;
        List<String> roleCodes;
    }

    @Data
    public static class AddUserResponse extends GenUserEntity {

    }

    @Override
    public void initData() {

        final int ENP_CNT = 10;
        final int SALES_CNT = 7;
        final int CUSTOMER_CNT = 30;

        final int ITEM_CNT = 10000;

        final long ITEM_COST_MIN = 500;
        final long ITEM_COST_MAX = 19800;

        final int ITEM_PROFIT_MIN = 10;
        final int ITEM_PROFIT_MAX = 50;

        // 每个门店售卖某个商品的概率
        final int CUSTOMER_ITEM_SELECT_PERCENT = 30;
        // 每个售货员当天来特定门店的概率
        final int CUSTOMER_SALES_SELECT_PERCENT = 15;
        // 售货员来该门店，每样商品送货的概率，万分制
        // 这个概率远小于真实情况，只不过我为了导入快点。正常概率，我们认为一周送2次货，拍2800更合适
        final int ITEM_SALES_SELECT_PERCENT = 25;

        final int ITEM_SALES_CNT_MIN = 10;
        final int ITEM_SALES_CNT_MAX = 1000;
        final String DAY_BEGIN = "2021-01-01";
        final String DAY_END = "2024-12-31";

        Map<Long,List<GenUserEntity>> salseManMap = new HashMap<>();

        Map<Long,List<GenCustomerEntity>> customerMap = new HashMap<>();
        Map<Long,List<GenItemEntity>> itemMap = new HashMap<>();
        Map<Long,List<GenItemEntity>> customerItemMap = new HashMap<>();


        RestClient restClient = RestClient.create();

        // 生成企业
        List<GenEnterpriseEntity> entList = new ArrayList<>();
        List<GenUserEntity> bossEntList = new ArrayList<>();
        for(int i = 1; i <= ENP_CNT; i++) {

            RegisterRequest registerRequest = new RegisterRequest();
            registerRequest.setBossUserName(String.format("test_adm_%03d",i));
            registerRequest.setEnpName(String.format("test_enp_%03d",i));
            registerRequest.setEnpDesc(String.format("测试公司%03d",i));
            registerRequest.setBossNickName(String.format("test_adm_%03d",i));
            registerRequest.setBossUserPassword("123456");

            RestResponse<RegisterResponse> response = restClient.post().uri("http://localhost:8080/api/account/register")
                    .body(registerRequest).retrieve().body(new ParameterizedTypeReference<RestResponse<RegisterResponse>>() {});
            GenEnterpriseEntity enterpriseEntity = response.getData().getEnterpriseInfo();
            entList.add(enterpriseEntity);
            bossEntList.add(response.getData().getUserInfo());
        }
        // 为每个企业添加员工
        for(int i = 1; i <= ENP_CNT; i++) {
            String bossUserName = String.format("test_adm_%03d",i);
            String bossUserPassword = "123456";

            LoginRequest loginRequest = new LoginRequest();
            loginRequest.setUsername(bossUserName);
            loginRequest.setPassword(bossUserPassword);

            RestResponse<LoginResponse> loginResponseRestResponse = restClient.post()
                    .uri("http://localhost:8080/api/account/login")
                    .body(loginRequest).retrieve().body(new ParameterizedTypeReference<RestResponse<LoginResponse>>() {});

            GenEnterpriseEntity enterpriseEntity = loginResponseRestResponse.getData().getEnterpriseInfo();

            List<GenUserEntity> userList = new ArrayList<>();
            salseManMap.put(enterpriseEntity.getId(), userList);

            for(int j=1; j <= SALES_CNT; j++) {
                AddUserRequest addUserRequest = new AddUserRequest();
                addUserRequest.setName(String.format("test_%s_sales_%03d","enp_"+i,j));
                addUserRequest.setNickname(String.format("test_%s_sales_%03d","enp_"+i,j));
                addUserRequest.setRoleCodes(Arrays.asList("ep_salesman"));

                RestResponse<AddUserResponse> addUserResponseRestResponse = restClient.post()
                        .uri("http://localhost:8080/api/account/addUser")
                        .body(addUserRequest)
                        .header("auth",loginResponseRestResponse.getData().getToken())
                        .retrieve().body(new ParameterizedTypeReference<RestResponse<AddUserResponse>>() {});

                userList.add(addUserResponseRestResponse.getData());
            }

        }

        for(GenEnterpriseEntity enterpriseEntity : entList) {

            DatasourceSetUtil.setDbPrompt(enterpriseEntity.getDbCode());

            // 为每个企业生成门店
            int customerCnt = CUSTOMER_CNT;
            List<GenCustomerEntity> customerEntityList = new ArrayList<>();
            for(int i = 1; i <= customerCnt; i++) {
                GenCustomerEntity customerEntity = new GenCustomerEntity();
                customerEntity.createInit();
                customerEntity.setName(String.format("%s_customer_%03d", enterpriseEntity.getEnpName(),i));
                customerEntity.setTestData(true);
                customerEntity.setEnpId(enterpriseEntity.getId());
                customerEntity.setEnpCode(enterpriseEntity.getEnpCode());
                customerEntityList.add(customerEntity);
            }
            mCustomerDbService.saveBatch(customerEntityList);
            customerMap.put(enterpriseEntity.getId(), customerEntityList);
            // 为每个企业生成商品
            int itemCnt = ITEM_CNT;
            List<GenItemEntity> itemEntityList = new ArrayList<>();
            for(int i=1;i<=itemCnt;i++){
                GenItemEntity itemEntity = new GenItemEntity();
                itemEntity.createInit();
                itemEntity.setName(String.format("%s_item_%03d", enterpriseEntity.getEnpName(),i));
                long cost = RandomUtil.randomLong(ITEM_COST_MIN, ITEM_COST_MAX);
                itemEntity.setCost(cost);
                itemEntity.setTestData(true);
                itemEntity.setEnpId(enterpriseEntity.getId());
                itemEntity.setEnpCode(enterpriseEntity.getEnpCode());
                itemEntityList.add(itemEntity);
            }
            mItemDbService.saveBatch(itemEntityList);
            itemMap.put(enterpriseEntity.getId(), itemEntityList);

            // 确定每个门店的商品列表
            for(GenCustomerEntity customerEntity : customerEntityList) {
                List<GenItemEntity> itemList = new ArrayList<>();
                for(GenItemEntity itemEntity : itemEntityList) {
                    int rd =RandomUtil.randomInt(0,100);
                    if(rd < CUSTOMER_ITEM_SELECT_PERCENT){
                        itemList.add(itemEntity);
                    }
                }
                customerItemMap.put(customerEntity.getId(), itemList);
            }
            DatasourceSetUtil.clear();
        }

        LocalDate startDate = LocalDate.parse(DAY_BEGIN);
        LocalDate endDate = LocalDate.parse(DAY_END);

        //final ExecutorService executorService = Executors.newFixedThreadPool(20);

        while (!startDate.isAfter(endDate)) {
            log.info("==================>>导入日期"+startDate+"====================");
            // 遍历每个企业
            for(GenEnterpriseEntity enterpriseEntity : entList) {
                List<GenUserEntity> salesManEntityList = salseManMap.get(enterpriseEntity.getId());
                List<GenCustomerEntity> customerEntityList = customerMap.get(enterpriseEntity.getId());
                List<GenConsignHeaderEntity> consignHeaderEntityList = new ArrayList<>();
                List<GenConsignEntity> consignEntityList = new ArrayList<>();

                log.info("导入企业"+enterpriseEntity.getEnpName());
                DatasourceSetUtil.setDbPrompt(enterpriseEntity.getDbCode());
                // 遍历旗下所有销售
                for(GenUserEntity salesManEntity : salesManEntityList) {
                    // 遍历旗下所有门店
                    for(GenCustomerEntity customerEntity : customerEntityList) {
                        int rd = RandomUtil.randomInt(0,100);
                        // 售货员不来该门店
                        if(rd >= CUSTOMER_SALES_SELECT_PERCENT){
                            continue;
                        }

                        //创建头表
                        GenConsignHeaderEntity consignHeaderEntity = new GenConsignHeaderEntity();
                        consignHeaderEntity.createInit();
                        consignHeaderEntity.setEnpId(enterpriseEntity.getId());
                        consignHeaderEntity.setEnpCode(enterpriseEntity.getEnpCode());
                        consignHeaderEntity.setBillNo(mBillNoUtil.getBillNo("csn"));

                        int hour = RandomUtil.randomInt(0,24);
                        int minute = RandomUtil.randomInt(0,59);
                        int second = RandomUtil.randomInt(0,59);
                        LocalDateTime billTime = startDate.atTime(hour, minute, second);
                        long billTimeKey = CommonUtil.LocalDateTimeToSecond(billTime);
                        String billTimeStr = LocalDateTimeUtil.formatNormal(billTime);

                        consignHeaderEntity.setBillTime(billTime);
                        consignHeaderEntity.setBillTimeKey(billTimeKey);

                        consignHeaderEntity.setCustomerId(customerEntity.getId());
                        consignHeaderEntity.setCustomerName(customerEntity.getName());
                        consignHeaderEntity.setSalesId(salesManEntity.getId());
                        consignHeaderEntity.setSalesName(salesManEntity.getNickName());

                        consignHeaderEntity.setDescription(billTimeStr+" "+customerEntity.getName()+" "+salesManEntity.getNickName());
                        consignHeaderEntity.setTestData(true);
                        consignHeaderEntityList.add(consignHeaderEntity);

                        List<GenItemEntity> itemEntityList = customerItemMap.get(customerEntity.getId());
                        for(GenItemEntity itemEntity : itemEntityList) {
                            rd = RandomUtil.randomInt(0,10000);
                            if(rd >= ITEM_SALES_SELECT_PERCENT){
                                continue;
                            }
                            int saleCnt = RandomUtil.randomInt(ITEM_SALES_CNT_MIN,ITEM_SALES_CNT_MAX);
                            GenConsignEntity consignEntity = new GenConsignEntity();
                            consignEntity.createInit();
                            consignEntity.setEnpId(enterpriseEntity.getId());
                            consignEntity.setItemId(itemEntity.getId());
                            consignEntity.setItemName(itemEntity.getName());
                            consignEntity.setItemCnt(saleCnt);
                            consignEntity.setBillTimeKey(billTimeKey);
                            consignEntity.setHeaderId(consignHeaderEntity.getId());

                            int profitPercent = RandomUtil.randomInt(ITEM_PROFIT_MIN,ITEM_PROFIT_MAX);
                            long cost = (long)(itemEntity.getCost() * (1 + profitPercent/100.0));
                            consignEntity.setPrice(cost);
                            consignEntity.setTestData(true);
                            consignEntityList.add(consignEntity);
                        }
                    }
                }

                TransactionTemplate template = new TransactionTemplate(mTransactionManager);
                template.execute(status ->{
                    try{
                        mConsignHeaderDbService.saveBatch(consignHeaderEntityList);
                        mConsignDbService.saveBatch(consignEntityList);
                    }catch(Exception e){
                        status.setRollbackOnly();
                        log.error("存储销售单失败");
                        e.printStackTrace();
                        return false;
                    }
                    return true;
                });

                log.info("本轮销售单已提交导入");
                DatasourceSetUtil.clear();
            }
            startDate = startDate.plusDays(1l);
        }



    }
}
